From 0af094770c4ebabc56ff761a8bd215bc397c0f7e Mon Sep 17 00:00:00 2001 From: João Augusto Costa Branco Marado Torres Date: Tue, 5 Aug 2025 18:50:37 +0100 Subject: refactor: reading page review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Augusto Costa Branco Marado Torres --- src/pages/blog/read/[...slug].astro | 449 ------------------------------------ 1 file changed, 449 deletions(-) delete mode 100644 src/pages/blog/read/[...slug].astro (limited to 'src/pages/blog/read/[...slug].astro') diff --git a/src/pages/blog/read/[...slug].astro b/src/pages/blog/read/[...slug].astro deleted file mode 100644 index 71d0929..0000000 --- a/src/pages/blog/read/[...slug].astro +++ /dev/null @@ -1,449 +0,0 @@ ---- -import { type CollectionEntry, getCollection } from "astro:content"; -import { render } from "astro:content"; -import Translations from "@components/Translations.astro"; -import { toIso8601Full } from "@utils/datetime"; -import ReadingTime from "@components/ReadingTime.astro"; -import Keywords from "@components/Keywords.astro"; -import Citations from "@components/Citations.astro"; -import Signature from "@components/signature/Signature.astro"; -import CopyrightNotice from "@components/CopyrightNotice.astro"; -import { verifier as verifierPrototype } from "@lib/pgp/verify"; -import { getSigners, isTranslation } from "@lib/collection/helpers"; -import { get } from "@utils/anonymous"; -import Authors from "@components/signature/Authors.astro"; -import { getEntry } from "astro:content"; -import Base from "@layouts/Base.astro"; -import readingTime from "reading-time"; -import type { - Entry, - MicroEntry, - OriginalEntry, -} from "@lib/collection/schemas"; - -export async function getStaticPaths() { - const posts = await getCollection("blog"); - return posts.map((post) => ({ - params: { slug: post.id }, - props: post, - })); -} - -type Props = CollectionEntry<"blog">; - -const post = Astro.props; - -let original: OriginalEntry | MicroEntry; -if (isTranslation(post)) { - original = await getEntry(post.data.translationOf) as - | OriginalEntry - | MicroEntry; - - if (!original) { - throw new Error(`Original post not found for ${post.id}`); - } - - const originalAuthor = (original.data.signers ?? []).filter( - (s) => s.role === "author", - ).map((s) => s.entity.id)?.[0]; - const originalCoAuthors = new Set( - (original.data.signers ?? []).filter( - (s) => s.role === "co-author", - ).map((s) => s.entity.id), - ); - const translationAuthor = (post.data.signers ?? []).filter( - (s) => s.role === "author", - ).map((s) => s.entity.id)?.[0]; - const translationCoAuthors = new Set( - (post.data.signers ?? []).filter( - (s) => s.role === "co-author", - ).map((s) => s.entity.id), - ); - - if ( - (translationAuthor !== undefined && - translationAuthor !== originalAuthor) || - !translationCoAuthors.isSubsetOf(originalCoAuthors) - ) { - throw new Error( - `Post ${post.id} has mismatched (co-)authors from original post ${original.id}`, - ); - } - - const translators = (post.data.signers ?? []).filter( - (s) => s.role === "translator", - ).map((s) => s.entity.id); - - for (const translator of translators) { - if ( - originalAuthor === translator || originalCoAuthors.has(translator) - ) { - throw new Error( - `Translator ${translator} in ${post.id} is already a (co-)author in original post`, - ); - } - } -} else { - original = post; - if (post.data.signers?.some((x) => x.role === "translator")) { - throw new Error( - `Post ${post.id} is not a translation but has translators defined`, - ); - } -} - -// Add own post as a translation -const translationsSet = new Set( - (await getCollection( - "blog", - (x) => - (x.data.kind === "translation") && x.data.translationOf.id === - (post.data.kind === "translation" - ? post.data.translationOf.id - : post.id), - ) ?? []).map(({ id }) => id), -); - -translationsSet.add(post.id); -const translations = [...translationsSet.values()].map((id) => ({ - collection: post.collection, - id, -})); - -const signers = await getSigners(post); - -const verifier = await verifierPrototype.then((x) => x.clone()); - -// Add signers public keys to keyring -for (const { data } of signers.map(get("entity"))) { - if (data.publickey.armor !== undefined) { - verifier.addKeyFromArmor(data.publickey.armor); - } -} - -const verification = post.filePath !== undefined - ? await verifier.verify([ - new URL(`file://${Deno.cwd()}/${post.filePath}`), - ]) - : undefined; - -const { Content } = await render(post); - -const { lang } = post.data; - -const commit = await verification?.commit; - -const reading = post.body ? readingTime(post.body, {}) : undefined; -const minutes = reading === undefined - ? undefined - : Math.ceil(reading.minutes); -const estimative = reading === undefined - ? undefined - : new Intl.DurationFormat(lang, { - style: "long", - }).format({ minutes }); -const duration = minutes === undefined - ? undefined - : `PT${Math.floor(minutes / 60) > 0 ? Math.floor(minutes / 60) + "H" : ""}${ - minutes % 60 > 0 ? minutes % 60 + "M" : "" - }`; - -const getOrUndefined = (k: string) => - k in post.data ? post.data[k as keyof typeof post.data] : undefined; -const author = { - "@type": "Person", -} as const; -const contributor = post.data.signers.filter(({ role }) => - role === "co-author" -).map(() => { - return { - "@type": "Person", - } as const; -}); -const translator = post.data.signers.filter(({ role }) => - role === "translator" -).map(() => { - return { - "@type": "Person", - } as const; -}); -const JSONLD = { - "@context": "https://schema.org", - "@type": "BlogPosting", - "@id": Astro.url.href, - articleBody: post.rendered?.html ?? post.body, - abstract: getOrUndefined("description"), - alternativeHeadline: getOrUndefined("subtitle"), - author, - citation: [].map(() => { - return { - "@type": "CreativeWork", - }; - }), - contributor, - copyrightHolder: [author, ...contributor, ...translator], - // copyrightNotice: post.data.license, // WORKAROUND - copyrightYear: post.data.dateCreated.getFullYear(), - creativeWorkStatus: "Published", - dateCreated: post.data.dateCreated.toISOString(), - dateModified: "dateUpdated" in post.data - ? post.data.dateUpdated?.toISOString() - : undefined, - // datePublished: undefined, // from git commit commit date - encodingFormat: "text/html", - headline: post.data.title, - inLanguage: post.data.lang, - isAccessibleForFree: true, - isBasedOn: isTranslation(post) - ? { - "@type": "BlogPosting", - "@id": new URL(`blog/read/${post.data.translationOf}`, Astro.site).href, - } - : undefined, - keywords: original.data.keywords, - license: post.data.license, // WORKAROUND - locationCreated: { - "@type": "Place", - // XXX: getOrUndefined("locationCreated"), - }, - mentions: [].map(() => { - return { - "@type": "Thing", - }; - }), - // publication: { - // "@type": "PublicationEvent", - // }, // from git commit - // publisher: { - // "@type": "Person", - // }, // from git commit - text: post.rendered?.html ?? post.body, - timeRequired: post.body !== undefined ? duration : undefined, - translationOf: isTranslation(post) - ? { - "@type": "BlogPosting", - "@id": new URL(`blog/read/${post.data.translationOf}`, Astro.site).href, - } - : undefined, - translator, - // version: undefined // TODO - wordCount: reading?.words, - workTranslations: translations.filter(({ id }) => id !== post.id).map(( - { id }, - ) => ({ - "@type": "BlogPosting", - "@id": new URL(`blog/read/${id}`, Astro.site).href, - })), - description: getOrUndefined("description"), - name: post.data.title, - url: Astro.url.href, -} as const; ---- - - -
-
- -
-

{post.data.title}

- { - "subtitle" in post.data && ( -

- {post.data.subtitle} -

- ) - } -
- { - "description" in post.data && post.data.description && - ( -
-

Resumo

- { - post.data.description.split(new RegExp("\\s{2,}")) - .map(( - x, - ) =>

{x}

) - } -
- ) - } - {verification && } -
- { - verification?.verifications && - ( - - ) - } -
-
Data de criação
-
- -
- { - post.data.dateUpdated && ( -
Última atualização
- -
- ) - } - { - "locationCreated" in post.data && - post.data.locationCreated && ( -
- Local de criação -
- {post.data.locationCreated} -
- ) - } -
- -
-
-
-
- { - "keywords" in original.data && ( - - ) - } - { - "relatedPosts" in original.data && ( - - ) - } - -
-
- - - - - - - -- cgit v1.2.3